#region Copyright & License
/* Tyng.Data
 * Copyright (c) 2007, Paul Tyng, All rights reserved.
 * Code licensed under the BSD License:
 * http://www.opensource.org/licenses/bsd-license.php
 * Downloaded from: http://code.google.com/p/tyngdata/
*/
#endregion

using System;

namespace Tyng.Data
{
	/// <summary>
	/// This class represents a field / column in StreamDataReader implementations.
	/// </summary>
    [Serializable]
	public class Field
	{
        /// <summary>
        /// String used to express NULL within a text file of data.
        /// </summary>
        /// <remarks>
        /// Blank in the file corresponds to an empty string, instead, the string "NULL" should be used.
        /// </remarks>
        public const string DefaultNullString = "NULL";

		private string _header;
		private Type _type;
		private IFieldConverter _ifc = null;
        private bool _checkForNull;
        private string _nullString = DefaultNullString;
        bool _trimLeft = true;
        bool _trimRight = true;
        private bool _blankAsNull;

		#region Constructors
		/// <summary>
		/// Creates a new field instance
		/// </summary>
		/// <param name="name">Name (Column Header) of the field</param>
		public Field(string name)
		{
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");

			_header = name;
			_type = typeof(string);
		}

		/// <summary>
		/// Creates a new field instance
		/// </summary>
		/// <param name="name">Name (Column Header) of the field</param>
        /// <param name="blankAsNull">Flag indicating a blank value is interpreted as <c>DBNull.Value</c></param>
        public Field(string name, bool blankAsNull)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");

            _header = name;
            _type = typeof(string);
            _blankAsNull = blankAsNull;
        }

		/// <summary>
		/// Creates a new field instance
		/// </summary>
		/// <param name="name">Name (Column Header) of the field</param>
		/// <param name="ifc">IFieldConverter implementation to convert data</param>
		public Field(string name, IFieldConverter ifc)
		{
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");

			_header = name;
			_type = typeof(string);
			_ifc = ifc;
		}

		/// <summary>
		/// Creates a new field instance
		/// </summary>
		/// <param name="name">Name (Column Header) of the field</param>
		/// <param name="type">Type of the field</param>
		public Field(string name, Type type)
		{
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");

			_header = name;
			_type = type;
		}

        /// <summary>
        /// Creates a new field instance
        /// </summary>
        /// <param name="name">Name (Column Header) of the field</param>
        /// <param name="type">Type of the field</param>
        /// <param name="checkForNullConstant">Flag indicating whether or not to interpret "NULL" as a DBNull</param>
        public Field(string name, Type type, bool checkForNullConstant)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");

            _header = name;
            _type = type;
            _checkForNull = checkForNullConstant;
        }

        /// <summary>
        /// Creates a new field instance
        /// </summary>
        /// <param name="name">Name (Column Header) of the field</param>
        /// <param name="type">Type of the field</param>
        /// <param name="ifc">IFieldConverter implementation to convert data</param>
        /// <param name="checkForNullConstant">Flag indicating whether or not to interpret "NULL" as a DBNull</param>
        public Field(string name, Type type, IFieldConverter ifc, bool checkForNullConstant)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");

            _header = name;
            _type = type;
            _ifc = ifc;
            _checkForNull = checkForNullConstant;
        }

		/// <summary>
		/// Creates a new field instance
		/// </summary>
		/// <param name="name">Name (Column Header) of the field</param>
		/// <param name="type">Type of the field</param>
		/// <param name="ifc">IFieldConverter implementation to convert data</param>
		public Field(string name, Type type, IFieldConverter ifc)
		{
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
			_header = name;
			_type = type;
			_ifc = ifc;
		}

        /// <summary>
        /// Create a new field instance, specifying the null string
        /// </summary>
        /// <param name="name">Name (Column Header) of the field</param>
        /// <param name="type">Type of the field</param>
        /// <param name="nullString">Null string for field data</param>
        public Field(string name, Type type, string nullString)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
            if (string.IsNullOrEmpty(nullString)) throw new ArgumentException("nullString");

            _header = name;
            _type = type;
            _checkForNull = true;
            _nullString = nullString;
        }

        /// <summary>
        /// Create a new field instance, specifying the null string
        /// </summary>
        /// <param name="name">Name (Column Header) of the field</param>
        /// <param name="type">Type of the field</param>
        /// <param name="nullString">Null string for field data</param>
        /// /// <param name="ifc">IFieldConverter implementation to convert data</param>
        public Field(string name, Type type, string nullString, IFieldConverter ifc)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
            if (string.IsNullOrEmpty(nullString)) throw new ArgumentException("nullString");

            _header = name;
            _type = type;
            _checkForNull = true;
            _nullString = nullString;
            _ifc = ifc;
        }
		#endregion

		/// <summary>
		/// Name of the field
		/// </summary>
		public string Name { get { return _header; } }
		/// <summary>
		/// Type of the field
		/// </summary>
		public Type DataType { get { return _type; } }

		/// <summary>
        /// Name of the type of the field
        /// </summary>
        public string DataTypeName { get { return _type.Name; } }

		/// <summary>
        /// Trim left whitespace from field value before conversion
        /// </summary>
        public bool TrimLeft { get { return _trimLeft; } }

        /// <summary>
        /// Trim right whitespace from field value before conversion
        /// </summary>
        public bool TrimRight { get { return _trimRight; } }

		/// <summary>
		/// Using the IFieldConverter for this field, convert a string to a typed object.
		/// </summary>
		/// <param name="data">String data to convert</param>
		/// <returns>Typed data</returns>
		public object ConvertFromString(string data)
		{
            if (_trimLeft) data = data.TrimStart(null); //null = default whitespace chars
            if (_trimRight) data = data.TrimEnd(null); //null = default whitespace chars

            if (_checkForNull && (data == _nullString || (_blankAsNull && data.Length == 0)))
                return DBNull.Value;

			if(_ifc == null)
				_ifc = TypeConverterFieldConverter.Default;
			
			return _ifc.ConvertFromString(_type, data);
		}

        /// <summary>
        /// The null string constant for this field.
        /// </summary>
        public string NullString { get { return _nullString; } }
		
		/// <summary>
		/// Object override
		/// </summary>
		/// <returns>Returns name or type of column if no name present</returns>
		public override string ToString()
		{
				return _header;

		}

		/// <summary>
		/// Object override
		/// </summary>
		/// <returns>Hash code</returns>
		public override int GetHashCode()
		{
			return base.GetHashCode ();
		}


	}
}
